// 双向绑定
class Zvue{
    constructor(options){
        this.options = options;
        this.$data = options.data;//获取数据
        this.$el = document.querySelector(options.el);//获取app对象
        this._directive = {}//这个东西就相当于是deps {dep1:{subs:[watcher]},dep2:{subs:[watcher]}}
        console.log('---options---',options);
        this.Observer(this.$data)
        this.Compile(this.$el)
    }
    // 劫持数据
    Observer(data){
        for (const key in data) {
            this._directive[key] =[]
            let val = data[key]
            let watchs = this._directive[key]
            Object.defineProperty(this.$data,key,{
                get:function(){
                    return val
                },
                set:function(newValue){
                    if(newValue !== val){
                        val = newValue;
                        console.log('---watchs--',watchs);
                        watchs.forEach(watcher =>{
                            watcher.update()
                        })
                    }
                }
            })
        }
    }
    // 指令解析
    Compile(el){
        let nodes = el.children;
        for (let i = 0; i < nodes.length; i++) {
            let node = nodes[i]
            // 递归 把嵌套的元素都找出来 判断是否有指令
            if(node.children.length){
                this.Compile(node)
            }
            if(node.hasAttribute('v-text')){
                let attrValue = node.getAttribute('v-text')
                this._directive[attrValue].push(new Watcher(node,this,attrValue,'innerHTML'))
            }
            if(node.hasAttribute('v-model')){
                let attrValue = node.getAttribute('v-model');
                this._directive[attrValue].push(new Watcher(node,this,attrValue,'value'))
                node.addEventListener('input', () => {
                    this.$data[attrValue] = node.value
                })
            }
        }
    }
}
// 订阅者
class Watcher{
    constructor(el,vm,exp,attr){
        this.el = el;
        this.vm = vm;
        this.exp = exp;
        this.attr = attr;
        this.update()
    }
    update(){
        this.el[this.attr] = this.vm.$data[this.exp]
    }
}
export default Zvue
// h(tag,props,children)函数就是去返回描述虚拟dom的结构的方法, 标签/属性/子元素
// diff的本质就是让程序知道应该去更新谁